﻿using System;
using CodeLibrary.Extensions.Common;

namespace CodeLibrary.Extensions
{
    public static class NumberExtension
    {
        public static TimeSpanSelector Weeks(this int i)
        {
            return new WeekSelector { ReferenceValue = i };
        }
        
        public static TimeSpanSelector Days(this int i)
        {
            return new DaysSelector { ReferenceValue = i };
        }
        
        public static TimeSpanSelector Years(this int i)
        {
            return new YearsSelector { ReferenceValue = i };
        }
        
        public static TimeSpanSelector Hours(this int i)
        {
            return new HourSelector { ReferenceValue = i };
        }
        
        public static TimeSpanSelector Minutes(this int i)
        {
            return new MinuteSelector { ReferenceValue = i };
        }
        
        public static TimeSpanSelector Seconds(this int i)
        {
            return new SecondSelector { ReferenceValue = i };
        }

        public static string ToWords(this long var)
        {
            return NumberArticulator.ConvertNumberToWord(var);
        }
        
        public static string ToWords(this int var)
        {
            return NumberArticulator.ConvertNumberToWord((long)var);
        }
        
        public static Age Age(this DateTime birthDate)
        {
            DateTime today = DateTime.Today;
            if (today < birthDate)
                throw new InvalidOperationException("birth date cannot be greater than the current date");

            int ageInYears;
            int ageInMonths;
            int ageInDays;

            CalculateAge(birthDate, today, out ageInYears, out ageInMonths, out ageInDays);
            return CreateAge(ageInYears, ageInMonths, ageInDays);
        }
        
        public static Age AgeAt(this DateTime birthDate, DateTime futureDate)
        {
            if (futureDate < birthDate)
                throw new InvalidOperationException("Future date cannot be less than the date of birth");
            int ageInYears;
            int ageInMonths;
            int ageInDays;

            CalculateAge(birthDate, futureDate, out ageInYears, out ageInMonths, out ageInDays);
            return CreateAge(ageInYears, ageInMonths, ageInDays);
        }
        
        public static string ToOrdinal(this int val)
        {
            if (val <= 0) throw new ArgumentException("Cardinal must be positive.");

            int lastTwoDigits = val % 100;
            int lastDigit = lastTwoDigits % 10;
            string suffix;
            switch (lastDigit)
            {
                case 1:
                    suffix = "st";
                    break;

                case 2:
                    suffix = "nd";
                    break;

                case 3:
                    suffix = "rd";
                    break;

                default:
                    suffix = "th";
                    break;
            }
            if (11 <= lastTwoDigits && lastTwoDigits <= 13)
            {
                suffix = "th";
            }
            return string.Format("{0}{1}", val, suffix);
        }

        private static void CalculateAge(DateTime adtDateOfBirth, DateTime referenceDate, out int noOfYears, out int noOfMonths, out int noOfDays)
        {
            DateTime adtCurrentDate = referenceDate;

            noOfDays = adtCurrentDate.Day - adtDateOfBirth.Day;
            noOfMonths = adtCurrentDate.Month - adtDateOfBirth.Month;
            noOfYears = adtCurrentDate.Year - adtDateOfBirth.Year;

            if (noOfDays < 0)
            {
                noOfDays += DateTime.DaysInMonth(adtCurrentDate.Year, adtCurrentDate.Month);
                noOfMonths--;
            }

            if (noOfMonths < 0)
            {
                noOfMonths += 12;
                noOfYears--;
            }
        }
        private static Age CreateAge(int years, int Months, int days)
        {
            Age age = new Age {Years = years, Months = Months, Days = days};
            return age;
        }
    }
}
